home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d18 / pasfile.arc / FILES.PAS < prev    next >
Pascal/Delphi Source File  |  1989-03-19  |  20KB  |  753 lines

  1. {
  2.   A flexible directory lister
  3.   written October, 1984
  4.   by Preston L. Bannister
  5.  
  6.   For each file found a line is written in the format specified by a macro
  7.   string.
  8. }
  9.  
  10. {$c+}
  11.  
  12. program main;
  13.  
  14. { i msdos.p }
  15. { ..... 8086 registers and flags -- for INTR() and MSDOS() calls ..... }
  16.  
  17. const
  18.   carry_flag     = 1;
  19.   parity_flag    = 4;
  20.   aux_carry_flag = 16;
  21.   zero_flag      = 64;
  22.   sign_flag      = 128;
  23.  
  24. type
  25.   registers =
  26.     record case integer of
  27.       1:(ax,bx,cx,dx,bp,si,di,ds,es,flags : integer);
  28.       2:(al,ah,bl,bh,cl,ch,dl,dh : byte)
  29.     end;
  30.  
  31. { ..... Standard MSDOS files, file attributes, and error codes ..... }
  32.  
  33. const
  34.   invalid_file = -1;
  35.  
  36.   stdin  = 0;   { standard input file handle }
  37.   stdout = 1;   { standard output file handle }
  38.   stderr = 2;   { standard error file handle }
  39.  
  40.   attribute_read_only = 1;
  41.   attribute_hidden    = 2;
  42.   attribute_system    = 4;
  43.   attribute_volume_id = 8;
  44.   attribute_directory = 16;
  45.   attribute_archive   = 32;
  46.  
  47.   no_error                  = 0;
  48.   error_invalid_function    = 1;
  49.   error_file_not_found      = 2;
  50.   error_path_not_found      = 3;
  51.   error_too_many_open_files = 4;
  52.   error_access_denied       = 5;
  53.   error_invalid_handle      = 6;
  54.   error_arena_trashed       = 7;
  55.   error_not_enough_memory   = 8;
  56.   error_invalid_block       = 9;
  57.   error_bad_environment     = 10;
  58.   error_bad_format          = 11;
  59.   error_invalid_access      = 12;
  60.   error_invalid_data        = 13;
  61.   error_invalid_drive       = 15;
  62.   error_current_directory   = 16;
  63.   error_not_same_device     = 17;
  64.   error_no_more_files       = 18;
  65. { i msdosio.p }
  66. { ..... Standard MSDOS file access routines ..... }
  67.  
  68.  
  69. { Create a file }
  70.  
  71. function createf (var fh : integer; var name; attribute : integer) : integer;
  72.   var reg : registers;
  73.   begin
  74.     reg.ah := $3C;
  75.     reg.ds := seg(name);
  76.     reg.dx := ofs(name);
  77.     reg.cx := attribute;
  78.     msdos(reg);
  79.     if (carry_flag and reg.flags) = 0 then
  80.       begin fh := reg.ax; createf := 0; end
  81.     else
  82.       begin fh := -1; createf := reg.ax; end;
  83.   end;
  84.  
  85.  
  86. {  Delete a file }
  87.  
  88. function deletef (var name) : integer;
  89.   var reg : registers;
  90.   begin
  91.     reg.ah := $41;
  92.     reg.ds := seg(name);
  93.     reg.dx := ofs(name);
  94.     msdos(reg);
  95.     if (carry_flag and reg.flags) = 0 then
  96.       deletef := 0
  97.     else
  98.       deletef := reg.ax;
  99.   end;
  100.  
  101.  
  102. { Open a file }
  103.  
  104. type file_access = (read_only, write_only, read_write);
  105.  
  106. function openf (var fh : integer; var name; access : file_access) : integer;
  107.   var reg : registers;
  108.   begin
  109.     reg.ah := $3D;
  110.     reg.ds := seg(name);
  111.     reg.dx := ofs(name);
  112.     reg.al := ord(access);
  113.     msdos(reg);
  114.     if (carry_flag and reg.flags) = 0 then
  115.       begin openf := 0; fh := reg.ax; end
  116.     else
  117.       begin openf := reg.ax; fh := -1; end;
  118.   end;
  119.  
  120.  
  121. { Close a file handle }
  122.  
  123. procedure closef (fh : integer);
  124.   var reg : registers;
  125.   begin
  126.     reg.ah := $3E;
  127.     reg.bx := fh;
  128.     msdos(reg);
  129.   end;
  130.  
  131.  
  132. { Read from a file }
  133.  
  134. function readf (fh : integer; var buffer; var bytes : integer) : integer;
  135.   var reg : registers;
  136.   begin
  137.     reg.ah := $3F;
  138.     reg.ds := seg(buffer);
  139.     reg.dx := ofs(buffer);
  140.     reg.cx := bytes;
  141.     reg.bx := fh;
  142.     msdos(reg);
  143.     if (carry_flag and reg.flags) = 0 then
  144.       begin readf := 0; bytes := reg.ax; end
  145.     else
  146.       begin readf := reg.ax; bytes := 0; end;
  147.   end;
  148.  
  149.  
  150. { Write to a file }
  151.  
  152. function writef (fh : integer; var buffer; var bytes : integer) : integer;
  153.   var reg : registers;
  154.   begin
  155.     reg.ah := $40;
  156.     reg.ds := seg(buffer);
  157.     reg.dx := ofs(buffer);
  158.     reg.cx := bytes;
  159.     reg.bx := fh;
  160.     msdos(reg);
  161.     if (carry_flag and reg.flags) = 0 then
  162.       begin writef := 0; bytes := reg.ax; end
  163.     else
  164.       begin writef := reg.ax; bytes := 0; end;
  165.   end;
  166. { i lookup.p }
  167. {
  168.   Access to the file system - get/set current drive/path and file lookup
  169.   written October, 1984
  170.   by Preston L. Bannister
  171.   -- depends on MSDOS.P
  172. }
  173.  
  174.  
  175. { Get the text of the current directory path on the given drive
  176.   - assumes at least 64 bytes availible for path name
  177. }
  178.  
  179.  
  180. function get_path (drive : integer; var path_name) : integer;
  181.   var reg : registers;
  182.   begin
  183.     reg.ah := $47;
  184.     reg.ds := seg(path_name);
  185.     reg.si := ofs(path_name);
  186.     reg.dl := drive;
  187.     msdos(reg);
  188.     if (carry_flag and reg.flags) = 0 then
  189.       get_path := no_error
  190.     else
  191.       get_path := reg.ax;
  192.   end;
  193.  
  194.  
  195. { Change the current directory }
  196.  
  197. function set_path (var path_name) : integer;
  198.   var reg : registers;
  199.   begin
  200.     reg.ah := $3B;
  201.     reg.ds := seg(path_name);
  202.     reg.dx := ofs(path_name);
  203.     msdos(reg);
  204.     if (carry_flag and reg.flags) = 0 then
  205.       set_path := no_error
  206.     else
  207.       set_path := reg.ax;
  208.   end;
  209.  
  210.  
  211. { Set disk transfer address }
  212.  
  213. procedure set_dma (var buffer);
  214.   var reg : registers;
  215.   begin
  216.     reg.ah := $1A;
  217.     reg.ds := seg(buffer);
  218.     reg.dx := ofs(buffer);
  219.     msdos(reg);
  220.   end;
  221.  
  222.  
  223. { Set the default drive }
  224.  
  225. procedure set_default_drive (drive : integer);
  226.   var reg : registers;
  227.   begin
  228.     reg.ah := $0E;
  229.     reg.dl := drive;
  230.     msdos(reg);
  231.   end;
  232.  
  233.  
  234. { Get the default drive }
  235.  
  236. function get_default_drive : integer;
  237.   var reg : registers;
  238.   begin
  239.     reg.ah := $19;
  240.     msdos(reg);
  241.     get_default_drive := reg.al;
  242.   end;
  243.  
  244.  
  245. { Get the number of logical drives }
  246.  
  247. function number_of_drives : integer;
  248.   var reg : registers;
  249.   begin
  250.     reg.ah := $19;
  251.     msdos(reg);
  252.     reg.ah := $0E;
  253.     reg.dl := reg.al;
  254.     msdos(reg);
  255.     number_of_drives := reg.al;
  256.   end;
  257.  
  258.  
  259. { the buffer used by the find first/next routines }
  260.  
  261. type file_info =
  262.   record
  263.     attr : byte;
  264.     time : integer;
  265.     date : integer;
  266.     size_l : integer;
  267.     size_h : integer;
  268.     pname : array [1..13] of char;
  269.   end;
  270.  
  271. type find_buf =
  272.   record
  273.    { CAVEAT PROGRAMMER ---> }
  274.     sattr       : byte;
  275.     drive       : byte;
  276.     name        : array [1..11] of char;
  277.     last_ent    : integer;
  278.     this_dpb    : ^ integer;
  279.     dir_start   : integer;
  280.    { <--- CAVEAT PROGRAMMER }
  281.     info        : file_info;
  282.   end;
  283.  
  284.  
  285. { Find the first file to match the given spec }
  286.  
  287. function find_first (var buf : find_buf; var name; attr : integer) : integer;
  288.   var reg : registers;
  289.   begin
  290.     set_dma(buf);
  291.     reg.ah := $4E;
  292.     reg.ds := seg(name);
  293.     reg.dx := ofs(name);
  294.     reg.cx := attr;
  295.     msdos(reg);
  296.     if (carry_flag and reg.flags) = 0 then
  297.       find_first := no_error
  298.     else
  299.       find_first := reg.ax;
  300.   end;
  301.  
  302.  
  303. { Find the next file to match the previously given spec }
  304.  
  305. function find_next (var buf : find_buf) : integer;
  306.   var reg : registers;
  307.   begin
  308.     set_dma(buf);
  309.     reg.ah := $4F;
  310.     msdos(reg);
  311.     if (carry_flag and reg.flags) = 0 then
  312.       find_next := no_error
  313.     else
  314.       find_next := reg.ax;
  315.   end;
  316.  
  317.  
  318. { Lookup the file with the given (path) name, return file info }
  319.  
  320. function lookup (var name; attr : integer; var info : file_info) : integer;
  321.   var buf : find_buf; error : integer;
  322.   begin
  323.     lookup := find_first(buf,name,attr);
  324.     info := buf.info;
  325.   end;
  326. { i chars.p }
  327.  
  328. type char_array = array [0..0] of char;
  329.  
  330. function scan_until (var s; ch : char; max : integer) : integer;
  331.   var i : integer; c : char_array absolute s;
  332.   begin
  333.     i := 0;
  334.     while (c[i] <> ch) and (i < max) do i := succ(i);
  335.     scan_until := i;
  336.   end;
  337.  
  338. function scan_back_until (var s; ch : char; max : integer) : integer;
  339.   var i : integer; c : char_array absolute s;
  340.   begin
  341.     i := 0;
  342.     while (c[-i] <> ch) and (i < max) do i := succ(i);
  343.     scan_back_until := i;
  344.   end;
  345.  
  346. function scan_while (var s; ch : char; max : integer) : integer;
  347.   var i : integer; c : char_array absolute s;
  348.   begin
  349.     i := 0;
  350.     while (c[i] = ch) and (i < max) do i := succ(i);
  351.     scan_while := i;
  352.   end;
  353.  
  354. function pop_token (var src, dst; max : integer; var n : integer) : integer;
  355.   var i, j : integer; s : char_array absolute src;
  356.   begin
  357.     i := scan_while(s[0],' ',max);
  358.     j := i + scan_until(s[i],' ',(max - i));
  359.     n := (j - i);
  360.     move(s[i],dst,n);
  361.     pop_token := j;
  362.   end;
  363.  
  364. procedure upcase_chars (var s; n : integer);
  365.   var i : integer; ch : char_array absolute s;
  366.   begin
  367.     for i := 0 to n - 1 do ch[i] := upcase(ch[i]);
  368.   end;
  369.  
  370. const digit : array [0..15] of char = '0123456789ABCDEF';
  371.  
  372. function hex_to_chars (h, n : integer; var s) : integer;
  373.   var c : char_array absolute s;
  374.   begin hex_to_chars := n;
  375.     while (n > 0) do
  376.       begin n := pred(n); c[n] := digit[h and $000F]; h := h shr 4; end;
  377.   end;
  378.  
  379. function dec_to_chars (d, n : integer; var s; zeros : boolean) : integer;
  380.   var c : char_array absolute s;
  381.   begin dec_to_chars := n;
  382.     repeat
  383.       n := pred(n); c[n] := digit[d mod 10]; d := d div 10;
  384.     until (n <= 0) or ((not zeros) and (d = 0));
  385.     while (n > 0) do begin n := pred(n); c[n] := ' '; end;
  386.   end;
  387.  
  388. function asciiz_to_chars (var a; n : integer; var s) : integer;
  389.   var c : char_array absolute a; m : integer; d : char_array absolute s;
  390.   begin asciiz_to_chars := n;
  391.     m := scan_until(c[0],#0,n);
  392.     move(c,d,m);
  393.     fillchar(d[m],n - m,' ');
  394.   end;
  395. { i vols.p }
  396.  
  397. { structures used by fcb_ calls }
  398.  
  399. type fcb_name = array [1..11] of char;
  400.  
  401. type _fcb =
  402.   record
  403.     flag : byte;
  404.     _6_2 : array [-6..-2] of byte;
  405.     attr : byte;
  406.     drive : byte;
  407.     name : fcb_name;
  408.     _12_16 : array [12..16] of byte;
  409.     new_name : fcb_name;
  410.   end;
  411.  
  412. type opened_fcb =
  413.   record
  414.     flag : byte;
  415.     _6_2 : array [-6..-2] of byte;
  416.     attr : byte;
  417.     drive : byte;
  418.     name : fcb_name;
  419.     rest : array [12..36] of integer;
  420.   end;
  421.  
  422. const any_name : fcb_name = '???????????';
  423.  
  424.  
  425. { Find the first file matching the name }
  426.  
  427. function fcb_find_first (
  428.                      drive, attr : byte;
  429.                      name : fcb_name;
  430.                      var out_fcb : opened_fcb
  431.                     ) : boolean;
  432.   var reg : registers; fcb : _fcb;
  433.   begin
  434.     set_dma(out_fcb);
  435.     fcb.flag  := $FF;
  436.     fcb.drive := drive;
  437.     fcb.attr  := attr;
  438.     fcb.name  := name;
  439.     reg.ah := $11;
  440.     reg.ds := seg(fcb);
  441.     reg.dx := ofs(fcb);
  442.     msdos(reg);
  443.     fcb_find_first := (reg.al = 0);
  444.   end;
  445.  
  446.  
  447. { Rename the file refered to by the FCB }
  448.  
  449. function fcb_rename (drive, attr : byte; name, new_name : fcb_name) : boolean;
  450.   var reg : registers; fcb : _fcb;
  451.   begin
  452.     fcb.flag  := $FF;
  453.     fcb.drive := drive;
  454.     fcb.attr  := attr;
  455.     fcb.name  := name;
  456.     fcb.new_name := new_name;
  457.     reg.ah := $17;
  458.     reg.ds := seg(fcb);
  459.     reg.dx := ofs(fcb);
  460.     msdos(reg);
  461.     fcb_rename := (reg.al = 0);
  462.   end;
  463.  
  464.  
  465. { Disk Reset - make sure next action checks disk first }
  466.  
  467. procedure disk_reset;
  468.   var reg : registers;
  469.   begin reg.ah := $0D; msdos(reg) end;
  470.  
  471.  
  472. { Get the volume id (label) for the disk in the given drive }
  473.  
  474. function get_volume_id (drive : byte; var name : fcb_name) : boolean;
  475.   var fcb : opened_fcb;
  476.   begin
  477.     get_volume_id := fcb_find_first(drive,attribute_volume_id,any_name,fcb);
  478.     name := fcb.name;
  479.   end;
  480.  
  481.  
  482. { Set the volume id (label) for the disk in the given drive }
  483.  
  484. function set_volume_id (drive : byte; new_name : fcb_name) : boolean;
  485.   var new_namez : string[16]; fh : integer;
  486.   begin
  487.     set_volume_id := true;
  488.     disk_reset;
  489.     if not fcb_rename(drive,attribute_volume_id,any_name,new_name) then
  490.       begin
  491.         new_namez := new_name + #0;
  492.         insert('.',new_namez,9);
  493.         if drive <> 0 then
  494.           begin
  495.             insert('@:',new_namez,1);
  496.             new_namez[1] := chr(ord('@') + drive);
  497.           end;
  498.         if createf(fh,new_namez[1],attribute_volume_id) = no_error then
  499.           closef(fh)
  500.         else
  501.           set_volume_id := false;
  502.       end;
  503.   end;
  504.  
  505. { end of includes }
  506.  
  507.  
  508. function time_to_chars (t : integer; var s) : integer;
  509.   var c : char_array absolute s; i : integer;
  510.   begin time_to_chars := 8;
  511.     i := dec_to_chars((t shr 11),2,c[0],true);
  512.     c[2] := ':';
  513.     i := dec_to_chars((t and $07E0) shr 5,2,c[3],true);
  514.     c[5] := ':';
  515.     i := dec_to_chars((t and $001F),2,c[6],true);
  516.   end;
  517.  
  518. function date_to_chars (d : integer; var s) : integer;
  519.   var c : char_array absolute s; i : integer;
  520.   begin date_to_chars := 8;
  521.     i := dec_to_chars(80 + (d shr 9),2,c[0],true);
  522.     c[2] := '-';
  523.     i := dec_to_chars((d and $01E0) shr 5,2,c[3],true);
  524.     c[5] := '-';
  525.     i := dec_to_chars((d and $001F),2,c[6],true);
  526.   end;
  527.  
  528. function attr_to_chars (a : integer; var s) : integer;
  529.   var c : char_array absolute s; i : integer;
  530.   begin attr_to_chars := 6;
  531.     fillchar(c[0],6,'-');
  532.     if (attribute_read_only and a) <> 0 then c[5] := 'r';
  533.     if (attribute_hidden    and a) <> 0 then c[4] := 'h';
  534.     if (attribute_system    and a) <> 0 then c[3] := 's';
  535.     if (attribute_volume_id and a) <> 0 then c[2] := 'v';
  536.     if (attribute_directory and a) <> 0 then c[1] := 'd';
  537.     if (attribute_archive   and a) <> 0 then c[0] := 'a';
  538.   end;
  539.  
  540. function kbytes_to_chars (var f : find_buf; var s) : integer;
  541.   var c : char_array absolute s; i, k : integer;
  542.   begin kbytes_to_chars := 5;
  543.     k := (f.info.size_l + 1023) shr 10 + (f.info.size_h shl 6);
  544.     i := dec_to_chars(k,4,c[0],false);
  545.     c[4] := 'k';
  546.   end;
  547.  
  548. type string80 = string[80];
  549.  
  550. function string_to_chars (var str : string80; var s) : integer;
  551.   begin string_to_chars := length(str);
  552.     move(str[1],s,length(str));
  553.   end;
  554.  
  555. const volume_id : fcb_name = '...........';
  556.  
  557. function vol_to_chars (var s) : integer;
  558.   begin vol_to_chars := sizeof(volume_id);
  559.     move(volume_id,s,sizeof(volume_id));
  560.   end;
  561.  
  562. var form : string[80];
  563.  
  564. {
  565.   Write out file information in the format specified by a template.
  566.   The recognized macro characters are listed in the constants.
  567. }
  568.  
  569.  
  570. procedure write_file_info (var f : find_buf; var branch : string80);
  571.   const
  572.     macro_prefix = '$';
  573.     c_time       = 'T';
  574.     c_date       = 'D';
  575.     c_path       = 'P';
  576.     c_gt         = 'G';
  577.     c_less       = 'L';
  578.     c_bar        = 'B';
  579.     c_file       = 'F';
  580.     c_attr       = 'A';
  581.     c_size_l     = '0';
  582.     c_size_h     = '1';
  583.     c_kbytes     = 'K';
  584.     c_volume     = 'V';
  585.   var
  586.     i, j, n : integer;
  587.     outs : string[80];
  588.   begin
  589.     i := 1; j := 1;
  590.     while (i <= length(form)) and (j < 80) do
  591.       begin
  592.         if form[i] = macro_prefix then
  593.           begin
  594.             i := succ(i);
  595.             case upcase(form[i]) of
  596.               macro_prefix : begin outs[j] := macro_prefix; j := j+1; end;
  597.               c_time    : j := j + time_to_chars(f.info.time,outs[j]);
  598.               c_date    : j := j + date_to_chars(f.info.date,outs[j]);
  599.               c_path    : j := j + string_to_chars(branch,outs[j]);
  600.               c_gt      : begin outs[j] := '>'; j := j+1; end;
  601.               c_less    : begin outs[j] := '<'; j := j+1; end;
  602.               c_bar     : begin outs[j] := '|'; j := j+1; end;
  603.               c_file    : j := j + asciiz_to_chars(f.info.pname[1],13,outs[j]);
  604.               c_attr    : j := j + attr_to_chars(f.info.attr,outs[j]);
  605.               c_size_l  : j := j + hex_to_chars(f.info.size_l,4,outs[j]);
  606.               c_size_h  : j := j + hex_to_chars(f.info.size_h,4,outs[j]);
  607.               c_kbytes  : j := j + kbytes_to_chars(f,outs[j]);
  608.               c_volume  : j := j + vol_to_chars(outs[j]);
  609.             end;
  610.           end
  611.         else
  612.           begin outs[j] := form[i]; j := succ(j); end;
  613.         i := succ(i);
  614.       end;
  615.     outs[0] := chr(j - 1);
  616.     write(outs);
  617.   end;
  618.  
  619.  
  620. function min (a, b : integer) : integer;
  621.   begin if a < b then min := a else min := b end;
  622.  
  623.  
  624. procedure find2 (var branch, leaf : string80; attr, levels : integer);
  625.   var f : find_buf; path : string80; error, i : integer; dir : string[14];
  626.   begin
  627.     if levels >= 1 then
  628.       begin
  629.         path := concat(branch,leaf);
  630.         path[length(path) + 1] := #0;
  631.  
  632.         { list all files on this level }
  633.         error := find_first(f,path[1],attr);
  634.         while error = no_error do
  635.           begin
  636.             write_file_info(f,branch); writeln;
  637.             error := find_next(f);
  638.           end;
  639.  
  640.         if levels >= 2 then
  641.           begin
  642.             path := concat(branch,'*.*');
  643.             path[length(path) + 1] := #0;
  644.  
  645.             { list all subdirectories to given level }
  646.             error := find_first(f,path[1],$FF);
  647.             while error = no_error do
  648.               begin
  649.                 if (attribute_directory and f.info.attr) <> 0 then
  650.                   begin
  651.                     dir[0] := chr(scan_until(f.info.pname,#0,13));
  652.                     move(f.info.pname,dir[1],length(dir));
  653.                     if (dir <> '.') and (dir <> '..') then
  654.                       begin
  655.                         path := concat(branch,dir);
  656.                         path[0] := succ(path[0]);
  657.                         path[length(path)] := '\';
  658.                         path[length(path) + 1] := #0;
  659.  
  660.                         find2(path,leaf,attr,levels - 1);
  661.                       end;
  662.                   end;
  663.                 error := find_next(f);
  664.               end;
  665.           end;
  666.       end;
  667.   end;
  668.  
  669. procedure do_find (var name : string80; attr, levels : integer);
  670.   var branch, leaf : string80; i : integer;
  671.   begin
  672.     branch := name;
  673.     i := min(scan_back_until(name[length(branch)],'\',length(branch)),
  674.              scan_back_until(name[length(branch)],'/',length(branch)));
  675.     leaf[0] := chr(i);
  676.     move(branch[1 + length(branch) - i],leaf[1],length(leaf));
  677.     branch[0] := chr(length(branch) - i);
  678.     find2(branch,leaf,attr,levels);
  679.   end;
  680.  
  681. var switch_char : char;
  682.  
  683. function get_switch_char : char;
  684.   var reg : registers;
  685.   begin
  686.     reg.ah := $37;
  687.     reg.al := 0;
  688.     msdos(reg);
  689.     get_switch_char := chr(reg.dl);
  690.   end;
  691.  
  692. const
  693.   default_fn   = '*.*';
  694.   default_attr = $FF;
  695.   default_form = '$f $d $t $a $k $v $p';
  696.  
  697. procedure process_command (var line : string80);
  698.   var fn, temp : string80; n, i, levels, attribute, fn_drive : integer;
  699.   begin
  700.     fn[0] := #0; form[0] := #0;
  701.     levels := 1; attribute := default_attr;
  702.     i := 1;
  703.     while (i < length(line)) do
  704.       begin
  705.         i := i + pop_token(line[i],temp[1],1 + length(line) - i,n);
  706.         temp[0] := chr(n);
  707.         if (temp[1] = switch_char) then
  708.           begin
  709.             case upcase(temp[2]) of
  710.               'F' : attribute := attribute_read_only or attribute_hidden
  711.                                  or attribute_system;
  712.               'D' : attribute := attribute_directory;
  713.               'S' : levels := 100;
  714.               'X' :
  715.                 begin
  716.                   i := i + scan_while(line[i],' ',1 + length(line) - i);
  717.                   form[0] := chr(1 + length(line) - i);
  718.                   move(line[i],form[1],length(form));
  719.                   i := length(line) + 1;
  720.                 end;
  721.             end
  722.           end
  723.         else if length(temp) > 0 then
  724.           fn := temp;
  725.       end;
  726.  
  727.     { check file name }
  728.     if length(fn) = 0 then fn := default_fn;
  729.     fn[length(fn) + 1] := #0;
  730.     upcase_chars(fn[1],length(fn));
  731.     for i := 1 to length(fn) do if fn[i] = '/' then fn[i] := '\';
  732.  
  733.     if fn[2] = ':' then
  734.       fn_drive := ord(upcase(fn[1])) - ord('@')
  735.     else
  736.       fn_drive := 0;
  737.     if not get_volume_id(fn_drive,volume_id) then
  738.       fillchar(volume_id,sizeof(volume_id),' ');
  739.  
  740.     if length(form) = 0 then form := default_form;
  741.     form[length(form) + 1] := #0;
  742.  
  743.     { call actual find routine }
  744.     do_find(fn,attribute,levels);
  745.   end;
  746.  
  747. var command_line : string80 absolute cseg:$80;
  748.  
  749. begin
  750.   switch_char := get_switch_char;
  751.   process_command(command_line);
  752. end.
  753.